﻿using System;
using System.IO;
using Providers;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace FSProviders
{
    /// <summary>
    /// Manage Queries
    /// </summary>
    public class QueryProvider : IQueryProvider
    {
        #region Public

        /// <summary>
        /// Save data to a text file
        /// </summary>
        /// <param name="fileName">The name of the file to save the data to</param>
        /// <param name="dataToSave">The data to save</param>
        /// <param name="errorMsg">Any error messages generated during the save process</param>
        /// <returns>True if the save was successfull, otherwise false</returns>
        public bool SaveText(string fileName, string dataToSave, out string errorMsg)
        {
            bool result;

            errorMsg = string.Empty;

            // Save the supplied data to the file name specified in "fileName"
            TextWriter textFile = null;
            try
            {
                textFile = new StreamWriter(fileName, false);
                textFile.Write(dataToSave);
                textFile.Flush();
                result = true;
            }
            catch (Exception ex)
            {
                // Something has gone wrong so report the error to the user
                result = false;
                errorMsg = ex.Message;
            }
            finally
            {
                // Ensure the stream is closed
                if (textFile != null)
                {
                    textFile.Close();
                    textFile.Dispose();
                }

            }

            return result;
        }

        /// <summary>
        /// Save data to a text file which has a number embedded in it
        /// </summary>
        /// <param name="fileName">The name of the file to save the data to</param>
        /// <param name="fileNum">A number to include in the file name (so data.txt would become data 1.txt)</param>
        /// <param name="dataToSave">The data to save</param>
        /// <param name="errorMsg">Any error messages generated during the save process</param>
        /// <returns>True if the save was successfull, otherwise false</returns>
        public bool SaveNumberedText(string fileName, int fileNum, string dataToSave, out string errorMsg)
        {
            // Get components of file name
            string extension = Path.GetExtension(fileName);
            string fileNameNoExt = Path.GetFileNameWithoutExtension(fileName);
            string filePath = Path.GetDirectoryName(fileName);

            // Rebuild the file name with the file number embedded in it
            string fileNameWithNumber = Path.Combine(filePath,
                string.Format("{0} {1}{2}", fileNameNoExt, fileNum.ToString(), extension));

            return SaveText(fileNameWithNumber, dataToSave, out errorMsg);
        }

        /// <summary>
        /// Load a text file and return the contents
        /// </summary>
        /// <param name="fileName">The name of the file to load</param>
        /// <param name="errorMsg">Any error messages generated during the load process</param>
        /// <returns>If successfull then the data loaded from the file, otherwise string.Empty</returns>
        public string LoadText(string fileName, out string errorMsg)
        {
            string result;

            errorMsg = string.Empty;

            // Load the text from the file specified in fileName
            TextReader textFile = null;
            try
            {
                textFile = new StreamReader(fileName);
                result = textFile.ReadToEnd();
            }
            catch (Exception ex)
            {
                // Something has gone wrong so return null and an error message
                result = null;
                errorMsg = ex.Message;
            }
            finally
            {
                // Ensure the stream is closed no matter what happens
                if (textFile != null)
                {
                    textFile.Close();
                    textFile.Dispose();
                }
            }

            return result;
        }

        /// <summary>
        /// Add the databases server and database name to the base file name
        /// </summary>
        /// <param name="baseFileName">The base file name</param>
        /// <param name="db">The database whose details we want to add to the base file name</param>
        /// <returns>The file name in the format [Base Filename] [Server Name] [Database Name]</returns>
        public string GetDatabaseServerFileName(string baseFileName, Models.Database db)
        {
            // Get components of the base file name
            string extension = Path.GetExtension(baseFileName);
            string fileNameNoExt = Path.GetFileNameWithoutExtension(baseFileName);
            string filePath = Path.GetDirectoryName(baseFileName);

            // Create a string for the server name and database name then remove illegal file name characters from it
            string dbServer = string.Format("{0} - {1}", db.DatabaseServer.ServerName, db.DatabaseName);
            dbServer = RemoveIllegalCharachtersFromPath(dbServer);

            // Construct the new filename
            string databaseServerFileName = Path.Combine(filePath,
                string.Format("{0} {1}{2}", fileNameNoExt, dbServer, extension));

            return databaseServerFileName;
        }

        #endregion Public

        #region Private

        /// <summary>
        /// Remove any characters that cannot be in a file name or path from the supplied file name or path
        /// </summary>
        /// <param name="fileName">The filename/path to remove illegal characters from</param>
        /// <returns>Clean filename/path</returns>
        private string RemoveIllegalCharachtersFromPath(string fileName)
        {
            string cleanFileName = fileName;

            if (!string.IsNullOrEmpty(cleanFileName))
            {
                // Build regular expression search pattern
                string regex = String.Format("[{0}]", Regex.Escape(new string(Path.GetInvalidFileNameChars())));
                Regex removeInvalidChars = new Regex(regex, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.CultureInvariant);

                // Scan our file name with the search pattern
                MatchCollection invalidCharMatches = removeInvalidChars.Matches(fileName);
                foreach (Match invalidChar in invalidCharMatches)
                {
                    cleanFileName = cleanFileName.Replace(invalidChar.Value, "_");
                }
            }

            return cleanFileName;
        }

        #endregion Private
    }
}
